package org.yylnb.openplatform.gateway.filter;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants;
import org.springframework.stereotype.Component;
import org.yylnb.openplatform.commons.constans.ApiTagInRedis;
import org.yylnb.openplatform.gateway.api.CacheService;
import org.yylnb.openplatform.gateway.utils.LocalCacheUtils;

import javax.servlet.http.HttpServletRequest;
import java.util.Map;

/**
 * 当前过滤器用于扣除冻结的钱或者是返回前面因为异常导致没有执行请求但是冻结的钱
 * 问题: 1 当前过滤器怎么知道前面是否发生过异常,2 如果知道发生了异常,怎么知道是在冻结之前还是冻结之后发生的异常
 *
 * @author RainLin
 * @date 2020/7/27 - 19:40
 */
@Component
public class FeePostFilter extends ZuulFilter {
    private static final Logger LOGGER = LoggerFactory.getLogger(FeePostFilter.class);

    private final ObjectMapper objectMapper;

    private final CacheService cacheService;


    public FeePostFilter(ObjectMapper objectMapper, CacheService cacheService) {
        this.objectMapper = objectMapper;
        this.cacheService = cacheService;
    }

    @Override
    public String filterType() {
        return FilterConstants.POST_TYPE;

    }

    @Override
    public int filterOrder() {
        return 50;
    }

    @Override
    public boolean shouldFilter() {
        RequestContext context = RequestContext.getCurrentContext();
        //如果前置过滤器拦截了,当前过滤器不启用,如果请求是一个非幂等的,当前过滤器也不启用,所以会有多个判断条件,只有全部都符合才启用
        HttpServletRequest request = context.getRequest();
        String method = request.getParameter("method");
        Map<String, String> apiRoutingMap = LocalCacheUtils.getMapping(ApiTagInRedis.API_MAPPING + method);
        String needfee = apiRoutingMap.get("needfee");
        //获取在前置过滤器设置的冻结标记,只有有钱并且冻结过才会执行
        Object freeze = context.get("freeze");
        return "1".equalsIgnoreCase(needfee) && freeze != null;
    }

    @Override
    public Object run() throws ZuulException {
        System.err.println("计费的后置过滤器执行");
        RequestContext context = RequestContext.getCurrentContext();
        //获取到冻结的钱
        Long freeze = (Long) context.get("freeze");
        Object cusId = context.get("cusId");
        boolean response = context.sendZuulResponse();
        //不管有没有异常,冻结金额都要删除,只不过异常的时候再加回去
        cacheService.hIncr(ApiTagInRedis.API_CUSTOMER + cusId, "freeze", -freeze);
        if (!response) {
            //出了异常,把冻结的钱给人家加回去
            cacheService.hIncr(ApiTagInRedis.API_CUSTOMER + cusId, "money", freeze);
        }
        //TODO 如果代码出现异常,可以通过发送MQ消息 把上面的几个数据发出去,有一个消费者专门处理这类的操作,重新尝试一次,如果失败再次发送消息,可以设置一个阈值,比如5次,同一个事情五次都没有成功,则写入系统日志不再处理,等待人工干预
        return null;
    }

}
